/** System resolve replace start >>>>>>>>> */
var importMap = { imports: {}, scopes: {}, depcache: {}, integrity: {} }
var backslashRegEx = /\\/g
function resolveIfNotPlainOrUrl (relUrl, parentUrl) {
    if (relUrl.indexOf('\\') !== -1)
        relUrl = relUrl.replace(backslashRegEx, '/')
    // protocol-relative
    if (relUrl[0] === '/' && relUrl[1] === '/') {
        return parentUrl.slice(0, parentUrl.indexOf(':') + 1) + relUrl
    }
    // relative-url
    else if (relUrl[0] === '.' && (relUrl[1] === '/' || relUrl[1] === '.' && (relUrl[2] === '/' || relUrl.length === 2 && (relUrl += '/')) ||
        relUrl.length === 1 && (relUrl += '/')) ||
        relUrl[0] === '/') {
        var parentProtocol = parentUrl.slice(0, parentUrl.indexOf(':') + 1)
        // Disabled, but these cases will give inconsistent results for deep backtracking
        //if (parentUrl[parentProtocol.length] !== '/')
        //  throw Error('Cannot resolve');
        // read pathname from parent URL
        // pathname taken to be part after leading "/"
        var pathname
        if (parentUrl[parentProtocol.length + 1] === '/') {
            // resolving to a :// so we need to read out the auth and host
            if (parentProtocol !== 'file:') {
                pathname = parentUrl.slice(parentProtocol.length + 2)
                pathname = pathname.slice(pathname.indexOf('/') + 1)
            }
            else {
                pathname = parentUrl.slice(8)
            }
        }
        else {
            // resolving to :/ so pathname is the /... part
            pathname = parentUrl.slice(parentProtocol.length + (parentUrl[parentProtocol.length] === '/'))
        }

        if (relUrl[0] === '/')
            return parentUrl.slice(0, parentUrl.length - pathname.length - 1) + relUrl

        // join together and split for removal of .. and . segments
        // looping the string instead of anything fancy for perf reasons
        // '../../../../../z' resolved to 'x/y' is just 'z'
        var segmented = pathname.slice(0, pathname.lastIndexOf('/') + 1) + relUrl

        var output = []
        var segmentIndex = -1
        for (var i = 0; i < segmented.length; i++) {
            // busy reading a segment - only terminate on '/'
            if (segmentIndex !== -1) {
                if (segmented[i] === '/') {
                    output.push(segmented.slice(segmentIndex, i + 1))
                    segmentIndex = -1
                }
            }

            // new segment - check if it is relative
            else if (segmented[i] === '.') {
                // ../ segment
                if (segmented[i + 1] === '.' && (segmented[i + 2] === '/' || i + 2 === segmented.length)) {
                    output.pop()
                    i += 2
                }
                // ./ segment
                else if (segmented[i + 1] === '/' || i + 1 === segmented.length) {
                    i += 1
                }
                else {
                    // the start of a new segment as below
                    segmentIndex = i
                }
            }
            // it is the start of a new segment
            else {
                segmentIndex = i
            }
        }
        // finish reading out the last segment
        if (segmentIndex !== -1)
            output.push(segmented.slice(segmentIndex))
        return parentUrl.slice(0, parentUrl.length - pathname.length) + output.join('')
    }
}

function resolveUrl (relUrl, parentUrl) {
    return resolveIfNotPlainOrUrl(relUrl, parentUrl) || (relUrl.indexOf(':') !== -1 ? relUrl : resolveIfNotPlainOrUrl('./' + relUrl, parentUrl))
}

function getMatch (path, matchObj) {
    if (matchObj[path])
        return path
    var sepIndex = path.length
    do {
        var segment = path.slice(0, sepIndex + 1)
        if (segment in matchObj)
            return segment
    } while ((sepIndex = path.lastIndexOf('/', sepIndex - 1)) !== -1)
}

function applyPackages (id, packages) {
    var pkgName = getMatch(id, packages)
    if (pkgName) {
        var pkg = packages[pkgName]
        if (pkg === null) return
        if (id.length > pkgName.length && pkg[pkg.length - 1] !== '/') {
            targetWarning('W2', pkgName, pkg, 'should have a trailing \'/\'')
        }
        else
            return pkg + id.slice(pkgName.length)
    }
}

function targetWarning (code, match, target, msg) {
    console.warn(`Code: ${code},Package target ${msg}, resolving target '${target}' for ${match}`)
}

function resolveImportMap (importMap, resolvedOrPlain, parentUrl) {
    var scopes = importMap.scopes
    var scopeUrl = parentUrl && getMatch(parentUrl, scopes)
    while (scopeUrl) {
        var packageResolution = applyPackages(resolvedOrPlain, scopes[scopeUrl])
        if (packageResolution)
            return packageResolution
        scopeUrl = getMatch(scopeUrl.slice(0, scopeUrl.lastIndexOf('/')), scopes)
    }
    return applyPackages(resolvedOrPlain, importMap.imports) || resolvedOrPlain.indexOf(':') !== -1 && resolvedOrPlain
}

function resolveAndComposePackages (packages, outPackages, baseUrl, parentMap, parentUrl) {
    for (var p in packages) {
        var resolvedLhs = resolveIfNotPlainOrUrl(p, baseUrl) || p
        var rhs = packages[p]
        // package fallbacks not currently supported
        if (typeof rhs !== 'string')
            continue
        var mapped = resolveImportMap(parentMap, resolveIfNotPlainOrUrl(rhs, baseUrl) || rhs, parentUrl)
        if (!mapped) {
            targetWarning('W1', p, rhs, 'bare specifier did not resolve')
        }
        else
            outPackages[resolvedLhs] = mapped
    }
}

function resolveAndComposeImportMap (json, baseUrl, outMap) {
    console.log('resolveAndComposeImportMap', baseUrl, json)
    if (json.imports)
        resolveAndComposePackages(json.imports, outMap.imports, baseUrl, outMap, null)

    var u
    for (u in json.scopes || {}) {
        var resolvedScope = resolveUrl(u, baseUrl)
        resolveAndComposePackages(json.scopes[u], outMap.scopes[resolvedScope] || (outMap.scopes[resolvedScope] = {}), baseUrl, outMap, resolvedScope)
    }

    for (u in json.depcache || {})
        outMap.depcache[resolveUrl(u, baseUrl)] = json.depcache[u]

    for (u in json.integrity || {})
        outMap.integrity[resolveUrl(u, baseUrl)] = json.integrity[u]
}

function throwUnresolved (id, parentUrl) {
    throw Error('Unable to resolve bare specifier \'' + id + (parentUrl ? '\' from ' + parentUrl : '\''))
}

async function initSystem () {
    // SystemFile: "./scripting/systemjs/system.js",
    // ImportsMap: "/scripting/x/import-map.json"
    const import_map_json = origin + "/scripting/x/import-map.json";
    const resposne = await fetch(import_map_json);
    const json = await resposne.json();
    // prepareImport必须依赖document，无法直接使用
    // resolveAndComposeImportMap 在System.js中未暴露，无法直接使用，只能重写并在resolve中使用生成的数据
    resolveAndComposeImportMap(json, import_map_json, importMap);
    importScripts("./scripting/systemjs/system.js");

    System.resolve = function (id, parentUrl) {
        try {
            // Prefer import map (or other existing) resolution over the registerRegistry
            if (id.startsWith('cc'))
                return origin + '/fake_cc.js';
            parentUrl = parentUrl || origin;
            const result = resolveImportMap((importMap), resolveIfNotPlainOrUrl(id, parentUrl) || id, parentUrl) || throwUnresolved(id, parentUrl);
            console.log('System.resolve', id, parentUrl, result);
            if (!result)
                throw new Error('Unable to resolve ' + id);
            return result;
        } catch (err) {
            if (id in this.registerRegistry) {
                return id;
            }
            throw err;
        }
    }
}